﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace KLTP2UI
{
	static class DllMem
	{
		#region Extern
		[DllImport("MemMan.dll")]
		public static extern void MmInitialize();
		
		[DllImport("MemMan.dll")]
		public static extern void MmDeInitialize();
		
		[DllImport("MemMan.dll")]
		public static extern void MmReInitialize();

		[DllImport("MemMan.dll")]
		public static extern bool MmIsInitialized();


		
		[DllImport("MemMan.dll")]
		public static extern uint GetThreadsCountTotal();

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern uint GetThreadIndexForId(short threadId);

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern short GetThreadIdForIndex(uint threadIdx);

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern uint GetThreadEventsCount(uint threadIdx, bool useFilter);
		

		
		//The following block is backed by Data Access Layer for access simplicity
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		private static extern int GetEventTime(uint threadIdx, uint eventIdx, bool useFilter);

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		private static extern byte GetEventType(uint threadIdx, uint eventIdx, bool useFilter);
		//See CMemMan::GetTypeFast() for details

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr GetEventService(uint threadIdx, uint eventIdx, bool useFilter);

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		private static extern IntPtr GetEventMessage(uint threadIdx, uint eventIdx, bool useFilter);
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		private static extern void GetEventMessageEx(uint threadIdx, uint eventIdx, StringBuilder outBuffer, bool useFilter);
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		private static extern void GetEventTimeEx(uint threadIdx, uint eventIdx, StringBuilder outBuffer, bool useFilter);
		//end backed

		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)] 
		public static extern void AddString(string constData);
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)] 
		public static extern uint AddBlock(IntPtr changeableData, uint lengthOfBlock);



		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern void FilterAddType(string constData);
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern void FilterAddService(string constData);
		
		[DllImport("MemMan.dll")]
		public static extern void FilterClear();
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern void FilterApply(uint threadIdx);
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern uint FilterGetServicesCount();
		
		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr FilterGetServiceById(uint idx);

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern uint FilterGetActiveThreadIdx();

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern bool FilterIsActive();



		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)] 
		public static extern uint ParseBack(IntPtr constData, uint sizeInBytes);

		[DllImport("MemMan.dll", CallingConvention = CallingConvention.Cdecl)]
		public static extern ulong TermSearch(ulong searchPos, int direction, string term, bool shiftAtFirstIteration);
		#endregion

		#region MM Async Data Access Layer
		private static readonly Dictionary<int, StringBuilder> Buffers = new Dictionary<int, StringBuilder>();

		private static StringBuilder GetCleanThreadBuffer()
		{
			var k = Thread.CurrentThread.ManagedThreadId;
			if (!Buffers.ContainsKey(k))
				Buffers.Add(k, new StringBuilder(4096));
			Buffers[k].Clear();
			return Buffers[k];
		}

		public static bool IsThreadJoinable(Thread thread)
		{
			return thread != null && thread.IsAlive;
		}


		public static string ALGetEventService(uint threadIdx, uint eventIdx, bool useFilter)
		{
			return Marshal.PtrToStringAnsi(GetEventService(threadIdx, eventIdx, useFilter));
		}

		public static string ALGetEventMessageRaw(uint threadIdx, uint eventIdx, bool useFilter)
		{
			return Marshal.PtrToStringAnsi(GetEventMessage(threadIdx, eventIdx, useFilter));
		}

		public static string ALGetEventMessage(uint threadIdx, uint eventIdx, bool useFilter)
		{
			var buf = GetCleanThreadBuffer();
			GetEventMessageEx(threadIdx, eventIdx, buf, useFilter);
			return buf.ToString();
		}

		public static string ALGetEventTime(uint threadIdx, uint eventIdx, bool useFilter)
		{
			var buf = GetCleanThreadBuffer();
			GetEventTimeEx(threadIdx, eventIdx, buf, useFilter);
			return buf.ToString();
		}

		public static  int? ALGetEventType (uint threadIdx, uint eventIdx, bool useFilter)
		{
			var res = GetEventType(threadIdx, eventIdx, useFilter);
			return (res == 255 ? (int?)null : res);
		}

		public static int ALGetEventTimeRaw (uint threadIdx, uint eventIdx, bool useFilter)
		{
			return GetEventTime(threadIdx, eventIdx, useFilter);
		}
		#endregion
	}
}
